package main

import (
	"bufio"
	"fmt"
	"im_backend/pkg/encoding/binary"
	"net"
	"os"
	"time"
)

const (
	packetOffset  = 0
	headerOffset  = 4
	versionOffset = 6
	OpOffset      = 8
	seqOffset     = 12
	rawHeaderLen  = 28
	fromOffset    = 20
)

// Body: [rawHeaderLen ~ PacketLen]

func main() {
	var buf [512]byte
	addr := ":3101"
	tcpAddr, err := net.ResolveTCPAddr("tcp", addr)
	checkError(err)

	conn, err := net.DialTCP("tcp", nil, tcpAddr)
	conn.SetReadBuffer(512)
	conn.SetKeepAlive(true)
	checkError(err)
	// rAddr := conn.RemoteAddr()

	body := []byte("{\"mid\":123, \"room_id\":\"live://1000\", \"platform\":\"web\", \"accepts\":[1000,1001,1002]}")
	_, err = conn.Write(Encode(1, 7, 1, body))
	checkError(err)

	n, err := conn.Read(buf[0:])
	if n == rawHeaderLen {
		fmt.Println("empty body")
	}
	checkError(err)
	Decode(buf[0:n])

	// receive
	go func() {
		reader := bufio.NewReader(conn)
		for {
			var buf [512]byte
			n, err := reader.Read(buf[0:])
			checkError(err)
			if n == rawHeaderLen {
				fmt.Println("empty body")
			}
			Decode(buf[0:n])
		}
	}()

	// send hb pack
	for {
		b := Encode(1, 2, 1, nil)
		_, err := conn.Write(b)
		checkError(err)
		time.Sleep(3 * time.Second)
	}
}

func Encode(version, op, seq int, body []byte) []byte {
	b := make([]byte, rawHeaderLen)
	packetLen := rawHeaderLen + int32(len(body))
	binary.BigEndian.PutInt32(b[packetOffset:], packetLen)
	binary.BigEndian.PutInt16(b[headerOffset:], int16(rawHeaderLen))
	binary.BigEndian.PutInt16(b[versionOffset:], int16(version))
	binary.BigEndian.PutInt32(b[OpOffset:], int32(op))
	binary.BigEndian.PutInt64(b[seqOffset:], int64(seq))
	binary.BigEndian.PutInt64(b[fromOffset:], int64(0))
	b = append(b, body...)
	return b
}

func Decode(b []byte) {
	packLen := binary.BigEndian.Int32(b[packetOffset:headerOffset])
	headerLen := binary.BigEndian.Int16(b[headerOffset:versionOffset])
	version := binary.BigEndian.Int16(b[versionOffset:OpOffset])
	op := binary.BigEndian.Int32(b[OpOffset:seqOffset])
	seq := binary.BigEndian.Int64(b[seqOffset:])
	from := binary.BigEndian.Int64(b[fromOffset:])
	body := b[rawHeaderLen:]

	fmt.Println(">>>> PACKET RECEIVED <<<<")
	fmt.Printf("  > PACKET_LEN: %d <\n", packLen)
	fmt.Printf("  > HEADER_LEN: %d <\n", headerLen)
	fmt.Printf("  >   VERSION: %d  <\n", version)
	fmt.Printf("  >     OP: %d     <\n", op)
	fmt.Printf("  >    SEQ: %d     <\n", seq)
	fmt.Printf("  >    FROM: %d    <\n", from)
	fmt.Print("BODY: ")
	fmt.Println(string(body))
	fmt.Println(">>>>    END PACKET   <<<<\n\n\n")
}

func heartbeat(conn *net.TCPConn) {
	var buf [512]byte
	for {
		b := Encode(1, 2, 1, nil)
		_, err := conn.Write(b)
		checkError(err)
		n, err := conn.Read(buf[0:])
		if n == rawHeaderLen {
			fmt.Println("empty body")
		}
		checkError(err)
		Decode(buf[0:])
	}
}

func checkError(err error) {
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}
